#pragma once
#include<iostream>
using namespace std;
namespace hu
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr( T*& ptr)
			:_ptr(ptr)
		{
			cout << "auto_ptr(const T*& ptr=nullptr)" << endl;
		}

		auto_ptr(auto_ptr<T>& ptr)
			:_ptr(ptr._ptr)
		{
			ptr._ptr = nullptr;
		}

		~auto_ptr()
		{
			cout << "~auto_ptr()" <<" " << endl;
			delete _ptr;
			_ptr = nullptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T*& ptr)
			:_ptr(ptr)
		{
			cout << "unique_ptr(const T*& ptr=nullptr)" << endl;
		}

		unique_ptr(unique_ptr<T>& ptr) = delete;
		
		unique_ptr<T>& operator=(unique_ptr<T>& ptr) =delete;
		~unique_ptr()
		{
			cout << "~unique_ptr()" << " " << endl;
			delete _ptr;
			_ptr = nullptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}


	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_count(new int(1))
		{
		}
		shared_ptr(const shared_ptr<T>& Sp)
			:_ptr(Sp._ptr)
			,_count(Sp._count)
		{
			*(_count)++;
		}
		
		~shared_ptr()
		{
			cout << "~shared_ptr()" << endl;
			if (--(*_count) == 1)
			{
				cout << "delete" << endl;
				delete _ptr;
				delete _count;
			}
		}

		shared_ptr<int>& operator= (shared_ptr<int>& Sp)
		{
			if (Sp._ptr == _ptr)
			return *this;
			if (--(*_count) == 0)
			{
				delete _ptr;
				delete _count;
			}
			_ptr = Sp._ptr;
			_count = Sp._count;
			(*_count)++;
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
		int use_count()
		{
			return *_count;
		}

		T* get()
		{
			return _ptr;
		}

	private:
		T* _ptr;
		int* _count;
	};
}


template<class T>
class weak_ptr
{
public:
	weak_ptr()
		:_ptr(nullptr)
	{
	}
	weak_ptr(const shared_ptr<T>& Sp)
		:_ptr(Sp.get())
	{
	}
	weak_ptr<int>& operator= (weak_ptr<int>& Sp)
	{
		if (Sp._ptr == _ptr)
			return *this;
		_ptr = Sp._ptr;
		return *this;
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}
	

	T* get()
	{
		return _ptr;
	}

private:
	T* _ptr;

};


